import functools
from flask import (
    Blueprint, flash, g, redirect, render_template, request, session, url_for
)
from werkzeug.security import check_password_hash, generate_password_hash

from flaskr.db import get_db

bp = Blueprint('auth', __name__, url_prefix='/auth')

# 创建、编辑和删除博客文章将要求用户登录。装饰器可用于为应用它的每个视图检查这一点。
def login_required(view):
    """
    创建、编辑和删除博客文章将要求用户登录

    :param view: 视图函数
    :return:
    """
    @functools.wraps(view)
    def wrapper_view(**kwargs):
        # g.user 在登录后的 load_logged_in_user 中有赋值
        if g.user is None:
            # 未登录会跳转到登录页面
            return redirect(url_for('auth.login'))
        return view(**kwargs)
    return wrapper_view

@bp.before_app_request  # 视图函数运行前运行的函数，类似 SpringBoot 中的 拦截器之类的作用
def load_logged_in_user():
    """检查用户是否已登录"""
    # login 中设置的 session['user_id']
    user_id = session.get('user_id')
    if user_id is None:
        # session中无user_id,则清除全局变量g中存储的用户信息
        g.user = None
    else:
        # 已登录则根据session['user_id']把用户信息存入全局变量 g
        g.user = get_db().execute(
            'SELECT * FROM user WHERE id = ?', (user_id,)
        ).fetchone()

@bp.route('/register', methods=('GET', 'POST'))
def register():
    if request.method == 'POST':
        # request.form 是一种特殊类型的 dict，它映射提交的表单键和值
        username = request.form['username']
        password = request.form['password']
        db = get_db()
        error = None

        if not username:
            error = 'Username is required.'
        elif not password:
            error = 'Password is required.'

        if error is None:
            try:
                db.execute(
                    "INSERT INTO user (username, password) VALUES (?, ?)",
                    (username, generate_password_hash(password))
                )
                db.commit()
            except db.IntegrityError:
                error = "already registered."
            else:
                # url_for("auth.login") 指定 视图函数 auth.login 对应的路由 auth/login,
                # auth是bp = Blueprint('auth', __name__, url_prefix='/auth') 中第一个参数的 'auth'
                return redirect(url_for("auth.login"))
        flash(error)
    # 这里模板目录的路径都是相对于 应用(在此为 flaskr)目录的 templates 目录
    return render_template('auth/register.html')

@bp.route('/login', methods=("GET", "POST"))
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        db = get_db()
        error = None

        user = db.execute('SELECT * FROM user WHERE username = ?', (username,)).fetchone()
        if user is None:
            error = 'Incorrect username.'
        elif not check_password_hash(user['password'], password):
            error = 'Incorrect password.'

        if error is None:
            session.clear()
            session['user_id'] = user['id']
            return redirect(url_for('index'))
        flash(error)
    return render_template(('auth/login.html'))

@bp.route('/logout')
def logout():
    session.clear()
    return redirect(url_for('index'))

